Skip to main content

Minting policy

Now we can continue with a simple minting policy example.

The final result can be found at HarmonicLabs/simple-minting-pluts.

Project set up

We will start from the simple-minting-pluts example:

git clone https://github.com/HarmonicLabs/simple-minting-pluts.git
cd simple-minting-pluts
git remote remove origin

This gives us a simple project structure:

./simple-minting-pluts
├── contracts
│ └── minting.ts
├── next.config.js
├── next-env.d.ts
├── package.json
├── package-lock.json
├── src
│ ├── components
│ │ └── ConnectionHandler.tsx
│ ├── offchain
│ │ ├── getTxBuilder.ts
│ │ ├── mesh-utils.ts
│ │ └── mintNft.ts
│ ├── pages
│ │ ├── _app.tsx
│ │ ├── _document.tsx
│ │ └── index.tsx
│ └── styles
│ ├── globals.css
│ └── Home.module.css
└── tsconfig.json

Install dependencies

Just like the Hello plu-ts example; this project already comes with plu-ts as dependecy; all we need to do to then is to run

npm install

Project overview

From the project structure we see that the code can be found in the src folder and the contracts folder.

The contracts only file is the minting.ts one; which always success and exports the compiled result.

contracts/minting.ts
import { Address, PScriptContext, ScriptType, Credential, Script, compile, pfn, unit, passert } from "@harmoniclabs/plu-ts";

const contract = pfn([
PScriptContext.type
], unit)
(({ redeemer, tx, purpose }) => {
return passert.$(true);
});

export const compiledContract = compile(contract);

export const script = new Script(
ScriptType.PlutusV3,
compiledContract
);

export const scriptTestnetAddr = new Address(
"testnet",
Credential.script(script.hash)
);

The other file is the offchain/mintNft.ts, which includes the logic for building and executing the transaction for the NFT minting.

offchain/mintNft.ts
import { BrowserWallet } from "@meshsdk/core";
import { Value, Address } from "@harmoniclabs/plu-ts";
import { BlockfrostPluts } from "@harmoniclabs/blockfrost-pluts";
import { scriptTestnetAddr, script } from "../../contracts/minting";
import { toPlutsUtxo } from "./mesh-utils";
import getTxBuilder from "./getTxBuilder";

export async function mintNft(wallet: BrowserWallet, projectId: string): Promise<string> {

const recipient = Address.fromString(
await wallet.getChangeAddress()
);

const Blockfrost = new BlockfrostPluts({ projectId });

const txBuilder = await getTxBuilder(Blockfrost);
const myUTxOs = (await wallet.getUtxos()).map(toPlutsUtxo);

if (myUTxOs.length === 0) {
throw new Error("have you requested founds from the faucet?");
}

const utxo = myUTxOs.find(u => u.resolved.value.lovelaces > 15_000_000);

if (utxo === undefined) {
throw new Error("not enough ada");
}

const unsignedTx = await txBuilder.buildSync({
inputs: [{ utxo }],
changeAddress: recipient,
collaterals: [utxo],

// We need to declare a collateral return in order
// to store the minted token in the user wallet
collateralReturn: {
address: utxo.resolved.address,
value: Value.sub(utxo.resolved.value, Value.lovelaces(5_000_000))
},

// We need to declare the minting policy for the token
mints: [{
// This is the name and amount of tokens we want to mint
value: Value.singleAsset(
scriptTestnetAddr.paymentCreds.hash,
Buffer.from('Test Token'),
1
),
// We pass the script as inline and the redeemer address
script: {
inline: script,
policyId: scriptTestnetAddr.paymentCreds.hash,
redeemer: recipient.toData()
}
}]
});

const txStr = await wallet.signTx(unsignedTx.toCbor().toString());

return await Blockfrost.submitTx(txStr);
}

Test it out

To test it out run

npm run dev

And navigate to the specified url (eg. http://localhost:3000/);

Then connect your wallet.

And click on the Mint NFT button.

If everything works correctly you should be prompted to sign a transaction.